﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;

namespace CharacterCreation.Data.Models {
    /// <summary>
    /// The class defining the character
    /// </summary>
    [Serializable]
    public class Character : BasePersistanceClass {
        
        /// <summary>
        /// Gets or sets the Age
        /// </summary>
        public string Age {
            get { return _Age; }
            set {
                _Age = value;
                RaisePropertyChanged("Age");
            }
        }
        private string _Age;

        /// <summary>
        /// Gets or sets the Alignment
        /// </summary>
        public string Alignment {
            get { return _Alignment; }
            set {
                _Alignment = value;
                RaisePropertyChanged("Alignment");
            }
        }
        private string _Alignment;

        
        /// <summary>
        /// Gets or sets the Edge
        /// </summary>
        public int Edge {
            get { return _Edge; }
            set {
                _Edge = value;
                RaisePropertyChanged("Edge");
            }
        }
        private int _Edge;
                
        
        /// <summary>
        /// Gets or sets the Description
        /// </summary>
        public string Description {
            get { return _Description; }
            set {
                _Description = value;
                RaisePropertyChanged("Description");
            }
        }
        private string _Description;
        
        /// <summary>
        /// Gets or sets the Race
        /// </summary>
        public Race Race {
            get { return _Race;} 
            set {
                _Race = value;
                if (this.Strength == null) this.Strength = new CharacterStatistic<Strength>();
                this.Strength.RacialBonus = value.StrengthBonus;

                if (this.Dexterity == null) this.Dexterity = new CharacterStatistic<Dexterity>();
                this.Dexterity.RacialBonus = value.DexterityBonus;

                if (this.Fighting == null) this.Fighting = new CharacterStatistic<Fighting>();
                this.Fighting.RacialBonus = value.FightingBonus;

                if (this.Constitution == null) this.Constitution = new CharacterStatistic<Constitution>();
                this.Constitution.RacialBonus = value.ConstitutionBonus;

                if (this.Perception == null) this.Perception = new CharacterStatistic<Perception>();
                this.Perception.RacialBonus = value.PerceptionBonus;

                if (this.Intelligence == null) this.Intelligence = new CharacterStatistic<Intelligence>();
                this.Intelligence.RacialBonus = value.IntelligenceBonus;

                if (this.WillPower == null) this.WillPower = new CharacterStatistic<WillPower>();
                this.WillPower.RacialBonus = value.WillPowerBonus;

                if (this.Charisma == null) this.Charisma = new CharacterStatistic<Charisma>();
                this.Charisma.RacialBonus = value.CharismaBonus;

                if (this.HitPoints == null) this.HitPoints = new CharacterStatistic<HitPoints>();
                this.HitPoints.RacialBonus = value.HitPointsBonus;

                if (this.Essence == null) this.Essence = new CharacterStatistic<Essence>();
                this.Essence.RacialBonus = value.EssenceBonus;
            } 
        }
        private Race _Race;
        
        /// <summary>
        /// Gets or sets the Profession
        /// </summary>
        public Profession Profession { get; set; }
        
        /// <summary>
        /// Gets or sets the Skills
        /// </summary>
        public ObservableCollection<CharacterSkill> Skills {
            get { return _Skills; }
            set {
                _Skills = value;
                RaisePropertyChanged("Skills");
            }
        }

        public override void Register() {
            foreach (var skill in _Skills)
                registerSkill(skill);

            foreach (var special in _Specials)
                registerSpecial(special);

            _Skills.CollectionChanged += (s, e) => {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                    registerSkill((CharacterSkill)e.NewItems[0]);
            };

            _Specials.CollectionChanged += (s, e) => {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                    registerSpecial((CharacterSpecial)e.NewItems[0]);
            };
        }
        private ObservableCollection<CharacterSkill> _Skills;

        private void registerSkill(CharacterSkill skill) {
            skill.PropertyChanged += (s, e) => {
                if (e.PropertyName != "Score")
                    skill.CalculateSkillLevel(this);
            };
        }

        private void registerSpecial(CharacterSpecial special) {
            special.PropertyChanged += (s, e) => {
                if (e.PropertyName != "Score")
                    special.CalculateSpecialLevel(this);
            };
        }
        
        /// <summary>
        /// Gets or sets the Specials
        /// </summary>
        public ObservableCollection<CharacterSpecial> Specials {
            get { return _Specials; }
            set {
                _Specials = value;
                RaisePropertyChanged("Specials");
            }
        }
        private ObservableCollection<CharacterSpecial> _Specials;

                
        #region statistics
        public CharacterStatistic<Strength> Strength { get; set; }
        public CharacterStatistic<Dexterity> Dexterity { get; set; }
        public CharacterStatistic<Fighting> Fighting { get; set; }
        public CharacterStatistic<Constitution> Constitution { get; set; }
        public CharacterStatistic<Perception> Perception { get; set; }
        public CharacterStatistic<Intelligence> Intelligence { get; set; }
        public CharacterStatistic<WillPower> WillPower { get; set; }
        public CharacterStatistic<Charisma> Charisma { get; set; }
        public CharacterStatistic<HitPoints> HitPoints { get; set; }
        public CharacterStatistic<Essence> Essence { get; set; }
        #endregion statistics

        public int TotalRacialXP {
            get {
                int skillTotal = this.Skills.Sum(s => s.RacialXP);
                int specialTotal = this.Specials.Sum(s => s.RacialXP);
                int statTotal = Strength.RacialXP + Dexterity.RacialXP + Fighting.RacialXP + Constitution.RacialXP + Perception.RacialXP + Intelligence.RacialXP + WillPower.RacialXP + Charisma.RacialXP + HitPoints.RacialXP + Essence.RacialXP;
                return skillTotal + specialTotal + statTotal;
            }
        }

        public int TotalProfessionalXP {
            get {
                int skillTotal = this.Skills.Sum(s => s.ProfessionalXP);
                int specialTotal = this.Specials.Sum(s => s.ProfessionalXP);
                int statTotal = Strength.ProfessionalXP + Dexterity.ProfessionalXP + Fighting.ProfessionalXP + Constitution.ProfessionalXP + Perception.ProfessionalXP + Intelligence.ProfessionalXP + WillPower.ProfessionalXP + Charisma.ProfessionalXP + HitPoints.ProfessionalXP + Essence.ProfessionalXP;
                return skillTotal + specialTotal + statTotal;
            }
        }

        public int TotalMiscellaneousXP {
            get {
                int skillTotal = this.Skills.Sum(s => s.MiscellaneousXP);
                int specialTotal = this.Specials.Sum(s => s.MiscellaneousXP);
                int statTotal = Strength.MiscellaneousXP + Dexterity.MiscellaneousXP + Fighting.MiscellaneousXP + Constitution.MiscellaneousXP + Perception.MiscellaneousXP + Intelligence.MiscellaneousXP + WillPower.MiscellaneousXP + Charisma.MiscellaneousXP + HitPoints.MiscellaneousXP + Essence.MiscellaneousXP;
                return skillTotal + specialTotal + statTotal;
            }
        }

        public int TotalXP {
            get {
                int skillTotal = this.Skills.Sum(s => s.XP);
                int specialTotal = this.Specials.Sum(s => s.XP);
                int statTotal = Strength.XP + Dexterity.XP + Fighting.XP + Constitution.XP + Perception.XP + Intelligence.XP + WillPower.XP + Charisma.XP + HitPoints.XP + Essence.XP;
                return skillTotal + specialTotal + statTotal;
            }
        }


        public Character() { }

        [OnDeserializing]
        public void Deserializing(StreamingContext context) {
            this.Strength = new CharacterStatistic<Strength>();
        }
    }
}
